home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Shared Code / Reusable Source / memutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-16  |  16.0 KB  |  652 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     memutil.c
  4.  
  5.     This reusable module contains miscellaneous memory management 
  6.     utility routines.
  7.     
  8.     Copyright © 1994-1995, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13.  
  14. #include "def.h"
  15. #include "memutil.h"
  16.  
  17.  
  18.  
  19. static Size gCushion;                /* size of memory cushion */
  20. static Size gReserve;                /* size of memory reserve */
  21. static Handle gReserveBlock = nil;    /* reserve block */
  22. static Boolean gCritical = true;    /* true if current memory request is critical */
  23. static Boolean gCriticalSeq = false;    /* true if in sequence of critical memory requests */
  24.  
  25.  
  26.  
  27. /*----------------------------------------------------------------------------
  28.     MemoryAvailable 
  29.     
  30.     Check to see if memory is available, without using the cushion and reserve.
  31.             
  32.     Entry:    len = size of block to allocate.
  33.     
  34.     Exit:    function result = true if memory is available.
  35. ----------------------------------------------------------------------------*/
  36.  
  37. Boolean MemoryAvailable (Size len)
  38. {
  39.     long total, contig;
  40.     
  41.     if (gReserveBlock == nil || *gReserveBlock == nil) {
  42.         if (!RecoverReserveMemory()) return false;
  43.     }
  44.     PurgeSpace(&total, &contig);
  45.     return len + gCushion < contig;
  46. }
  47.  
  48.  
  49.  
  50. /*----------------------------------------------------------------------------
  51.     MyNewHandle 
  52.     
  53.     Allocate a new relocatable block. The contents of the new block are
  54.     cleared.
  55.             
  56.     Entry:    len = size of block to allocate.
  57.     
  58.     Exit:    *handle = new handle.
  59.             function result = error code.
  60. ----------------------------------------------------------------------------*/
  61.  
  62. OSErr MyNewHandle (Size len, void *handle)
  63. {
  64.     len = (Size)StripAddress((Ptr)len);
  65.     if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
  66.     gCritical = gCriticalSeq;
  67.     *(Handle*)handle = NewHandleClear(len);
  68.     gCritical = true;
  69.     return MemError();
  70. }
  71.  
  72.  
  73.  
  74. /*----------------------------------------------------------------------------
  75.     MyNewHandleCritical 
  76.     
  77.     Allocate a critical new relocatable block. The contents of the new block are
  78.     cleared. This function is for critical memory only - it is permitted to
  79.     use the memory cushion and reserve.
  80.             
  81.     Entry:    len = size of block to allocate.
  82.     
  83.     Exit:    *handle = new handle.
  84.             function result = error code.
  85. ----------------------------------------------------------------------------*/
  86.  
  87. OSErr MyNewHandleCritical (Size len, void *handle)
  88. {
  89.     len = (Size)StripAddress((Ptr)len);
  90.     *(Handle*)handle = NewHandleClear(len);
  91.     return MemError();
  92. }
  93.  
  94.  
  95.  
  96. /*----------------------------------------------------------------------------
  97.     MyDisposeHandle 
  98.     
  99.     Dispose a relocatable block.
  100.             
  101.     Entry:    handle = handle to block.
  102. ----------------------------------------------------------------------------*/
  103.  
  104. void MyDisposeHandle (void *handle)
  105. {
  106.     if (handle == nil) return;
  107.     DisposeHandle((Handle)handle);
  108. }
  109.  
  110.  
  111.  
  112. /*----------------------------------------------------------------------------
  113.     MyNewPtr 
  114.     
  115.     Allocate a new nonrelocatable block. The contents of the new block are
  116.     cleared.
  117.             
  118.     Entry:    len = size of block to allocate.
  119.     
  120.     Exit:    *ptr = new pointer.
  121.             function result = error code.
  122. ----------------------------------------------------------------------------*/
  123.  
  124. OSErr MyNewPtr (Size len, void *ptr)
  125. {
  126.     len = (Size)StripAddress((Ptr)len);
  127.     if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
  128.     gCritical = gCriticalSeq;
  129.     *(Ptr*)ptr = NewPtrClear(len);
  130.     gCritical = true;
  131.     return MemError();
  132. }
  133.  
  134.  
  135.  
  136. /*----------------------------------------------------------------------------
  137.     MyNewPtrCritical
  138.     
  139.     Allocate a critical new nonrelocatable block. The contents of the new
  140.     block are cleared. This function is for critical memory only - it is 
  141.     permitted to use the memory cushion and reserve.
  142.             
  143.     Entry:    len = size of block to allocate.
  144.     
  145.     Exit:    *ptr = new pointer.
  146.             function result = error code.
  147. ----------------------------------------------------------------------------*/
  148.  
  149. OSErr MyNewPtrCritical (Size len, void *ptr)
  150. {
  151.     len = (Size)StripAddress((Ptr)len);
  152.     *(Ptr*)ptr = NewPtrClear(len);
  153.     return MemError();
  154. }
  155.  
  156.  
  157.  
  158. /*----------------------------------------------------------------------------
  159.     MyDisposePtr 
  160.     
  161.     Dispose a nonrelocatable block.
  162.             
  163.     Entry:    ptr = pointer to block.
  164. ----------------------------------------------------------------------------*/
  165.  
  166. void MyDisposePtr (void *ptr)
  167. {
  168.     if (ptr == nil) return;
  169.     DisposePtr((Ptr)ptr);
  170. }
  171.  
  172.  
  173.  
  174. /*----------------------------------------------------------------------------
  175.     MySetHandleSize 
  176.     
  177.     Change the size of a relocatable block.
  178.             
  179.     Entry:    handle = handle to block.
  180.             len = new size of block.
  181.     
  182.     Exit:    function result = error code.
  183. ----------------------------------------------------------------------------*/
  184.  
  185. OSErr MySetHandleSize (void *handle, Size len)
  186. {
  187.     Size oldLen;
  188.     OSErr err = noErr;
  189.  
  190.     len = (Size)StripAddress((Ptr)len);
  191.     oldLen = GetHandleSize(handle);
  192.     if (!gCriticalSeq && oldLen < len) {
  193.         if (!MemoryAvailable(len-oldLen)) return memFullErr;
  194.     }
  195.     gCritical = gCriticalSeq;
  196.     SetHandleSize(handle, len);
  197.     gCritical = true;
  198.     err = MemError();
  199.     if (err == memFullErr) {
  200.         /* The Memory Manager is too stupid to do this itself. */
  201.         MoveHHi(handle);
  202.         CompactMem(maxSize);
  203.         gCritical = gCriticalSeq;
  204.         SetHandleSize(handle, len);
  205.         gCritical = true;
  206.         err = MemError();
  207.     }
  208.     if (err != noErr) return err;
  209.     if (oldLen >= len) return noErr;
  210.     if (gCriticalSeq || MemoryAvailable(0)) return noErr;
  211.     SetHandleSize(handle, oldLen);
  212.     return memFullErr;
  213. }
  214.  
  215.  
  216.  
  217. /*----------------------------------------------------------------------------
  218.     MySetHandleSizeCritical 
  219.     
  220.     Change the size of a critical relocatable block. This function is for 
  221.     critical memory only - it is permitted to use the memory cushion and 
  222.     reserve.
  223.             
  224.     Entry:    handle = handle to block.
  225.             len = new size of block.
  226.     
  227.     Exit:    function result = error code.
  228. ----------------------------------------------------------------------------*/
  229.  
  230. OSErr MySetHandleSizeCritical (void *handle, Size len)
  231. {
  232.     len = (Size)StripAddress((Ptr)len);
  233.     SetHandleSize(handle, len);
  234.     if (MemError() == memFullErr) {
  235.         /* The Memory Manager is too stupid to do this itself. */
  236.         MoveHHi(handle);
  237.         CompactMem(maxSize);
  238.         SetHandleSize(handle, len);
  239.     }
  240.     return MemError();
  241. }
  242.  
  243.  
  244.  
  245. /*----------------------------------------------------------------------------
  246.     MyGetHandleSize 
  247.     
  248.     Get the size of a relocatable block.
  249.             
  250.     Entry:    handle = handle to block.
  251.     
  252.     Exit:    function result = size of block.
  253. ----------------------------------------------------------------------------*/
  254.  
  255. long MyGetHandleSize (void *handle)
  256. {
  257.     return GetHandleSize((Handle)handle);
  258. }
  259.  
  260.  
  261.  
  262. /*----------------------------------------------------------------------------
  263.     MyHandToHand 
  264.     
  265.     Create a new relocatable block and copy an old relocatable block to it.
  266.             
  267.     Entry:    *handle = handle to block.
  268.     
  269.     Exit:    function result = error code.
  270.             *handle = handle to new copy of block.
  271. ----------------------------------------------------------------------------*/
  272.  
  273. OSErr MyHandToHand (void *theHndl)
  274. {
  275.     OSErr err = noErr;
  276.  
  277.     if (!gCriticalSeq && !MemoryAvailable(GetHandleSize(*(Handle*)theHndl))) 
  278.         return memFullErr;
  279.     gCritical = gCriticalSeq;
  280.     err = HandToHand((Handle*)theHndl);
  281.     gCritical = true;
  282.     return err;
  283. }
  284.  
  285.  
  286.  
  287. /*----------------------------------------------------------------------------
  288.     MyHandAndHand 
  289.     
  290.     Copy a relocatable block to the end of another relocatable block. 
  291.             
  292.     Entry:    srcHandle = source handle.
  293.             destHandle = destination handle.
  294.     
  295.     Exit:    function result = error code.
  296. ----------------------------------------------------------------------------*/
  297.  
  298. OSErr MyHandAndHand (void *srcHandle, void *destHandle)
  299. {    
  300.     long srcLen, destLen;
  301.     OSErr err = noErr;
  302.     
  303.     if (srcHandle == nil) return noErr;
  304.     srcLen = GetHandleSize(srcHandle);
  305.     destLen = GetHandleSize(destHandle);
  306.     err = MySetHandleSize(destHandle, srcLen + destLen);
  307.     if (err != noErr) return err;
  308.     BlockMoveData(*(Ptr*)srcHandle, *(Ptr*)destHandle + destLen, srcLen);
  309.     return noErr;
  310. }
  311.  
  312.  
  313.  
  314. /*----------------------------------------------------------------------------
  315.     MyPtrAndHand 
  316.     
  317.     Append data to the end of a relocatable block.
  318.             
  319.     Entry:    srcPtr = source pointer.
  320.             destHandle = destination handle.
  321.             len = amount of data to append.
  322.     
  323.     Exit:    function result = error code.
  324. ----------------------------------------------------------------------------*/
  325.  
  326. OSErr MyPtrAndHand (void *srcPtr, void *destHandle, Size len)
  327. {
  328.     OSErr err = noErr;
  329.  
  330.     len = (Size)StripAddress((Ptr)len);
  331.     if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
  332.     gCritical = gCriticalSeq;
  333.     err = PtrAndHand(srcPtr, destHandle, len);
  334.     gCritical = true;
  335.     return err;
  336. }
  337.  
  338.  
  339.  
  340. /*----------------------------------------------------------------------------
  341.     MyStrAndHand 
  342.     
  343.     Append a C-format string to the end of a relocatable block.
  344.             
  345.     Entry:    str = C-format string.
  346.             destHandle = destination handle.
  347.     
  348.     Exit:    function result = error code.
  349. ----------------------------------------------------------------------------*/
  350.  
  351. OSErr MyStrAndHand (char *str, void *destHandle)
  352. {
  353.     return MyPtrAndHand(str, destHandle, strlen(str));
  354. }
  355.  
  356.  
  357.  
  358. /*----------------------------------------------------------------------------
  359.     MyPtrToHand 
  360.     
  361.     Create a new relocatable block and copy data into it.
  362.             
  363.     Entry:    srcPtr = source pointer.
  364.             len = amount of data to copy.
  365.     
  366.     Exit:    function result = error code.
  367.             *destHandle = new handle.
  368. ----------------------------------------------------------------------------*/
  369.  
  370. OSErr MyPtrToHand (void *srcPtr, void *destHandle, Size len)
  371. {
  372.     OSErr err = noErr;
  373.  
  374.     len = (Size)StripAddress((Ptr)len);
  375.     if (!gCriticalSeq && !MemoryAvailable(len)) return memFullErr;
  376.     gCritical = gCriticalSeq;
  377.     err = PtrToHand(srcPtr, destHandle, len);
  378.     gCritical = true;
  379.     return err;
  380. }
  381.  
  382.  
  383.  
  384. /*----------------------------------------------------------------------------
  385.     MyPtrToXHand
  386.     
  387.     Copy data into an existing relocatable block.
  388.             
  389.     Entry:    srcPtr = source pointer.
  390.             destHandle = destination handle.
  391.             len = amount of data to copy.
  392.     
  393.     Exit:    function result = error code.
  394. ----------------------------------------------------------------------------*/
  395.  
  396. OSErr MyPtrToXHand (void *srcPtr, void *destHandle, Size len)
  397. {
  398.     Size oldLen;
  399.     OSErr err = noErr;
  400.  
  401.     len = (Size)StripAddress((Ptr)len);
  402.     oldLen = GetHandleSize(destHandle);
  403.     if (!gCriticalSeq && oldLen < len) {
  404.         if (!MemoryAvailable(len - oldLen)) return memFullErr;
  405.     }
  406.     gCritical = gCriticalSeq;
  407.     err = PtrToXHand(srcPtr, destHandle, len);
  408.     gCritical = true;
  409.     return err;
  410. }
  411.  
  412.  
  413.  
  414. /*----------------------------------------------------------------------------
  415.     MyHLock
  416.     
  417.     Lock a relocatable block.
  418.             
  419.     Entry:    handle = handle to lock.
  420. ----------------------------------------------------------------------------*/
  421.  
  422. void MyHLock (void *handle)
  423. {
  424.     if (handle == nil) return;
  425.     HLock((Handle)handle);
  426. }
  427.  
  428.  
  429.  
  430. /*----------------------------------------------------------------------------
  431.     MyHLockHi
  432.     
  433.     Move a relocatable block high and lock it.
  434.             
  435.     Entry:    handle = handle to lock.
  436. ----------------------------------------------------------------------------*/
  437.  
  438. void MyHLockHi (void *handle)
  439. {
  440.     if (handle == nil) return;
  441.     HLockHi((Handle)handle);
  442. }
  443.  
  444.  
  445.  
  446. /*----------------------------------------------------------------------------
  447.     MyHUnlock
  448.     
  449.     Unlock a relocatable block.
  450.             
  451.     Entry:    handle = handle to unlock.
  452. ----------------------------------------------------------------------------*/
  453.  
  454. void MyHUnlock (void *handle)
  455. {
  456.     if (handle == nil) return;
  457.     HUnlock((Handle)handle);
  458. }
  459.  
  460.  
  461.  
  462. /*----------------------------------------------------------------------------
  463.     MyHGetState
  464.     
  465.     Get the state of a memory block.
  466.             
  467.     Entry:    handle = handle to memory block.
  468.     
  469.     Exit:    function result = state.
  470. ----------------------------------------------------------------------------*/
  471.  
  472. char MyHGetState (void *handle)
  473. {
  474.     return HGetState(handle);
  475. }
  476.  
  477.  
  478.  
  479. /*----------------------------------------------------------------------------
  480.     MyHSetState
  481.     
  482.     Set the state of a memory block.
  483.             
  484.     Entry:    handle = handle to memory block.
  485.             state = state to set.
  486. ----------------------------------------------------------------------------*/
  487.  
  488. void MyHSetState (void *handle, char state)
  489. {
  490.     HSetState(handle, state);
  491. }
  492.  
  493.  
  494.  
  495. /*----------------------------------------------------------------------------
  496.     MyGrowZone
  497.     
  498.     Grow zone function for critical memory requests. 
  499.             
  500.     Entry:    cbNeeded = amount of memory needed.
  501.             
  502.     Exit:    function result = number of bytes freed.
  503. ----------------------------------------------------------------------------*/
  504.  
  505. static pascal long MyGrowZone (Size cbNeeded)
  506. {
  507.     long theA5, result;
  508.     
  509.     theA5 = SetCurrentA5();
  510.     if (gCritical && gReserveBlock != nil && 
  511.         *gReserveBlock != nil && gReserveBlock != GZSaveHnd()) 
  512.     {
  513.         EmptyHandle(gReserveBlock);
  514.         result = gReserve;
  515.     } else {
  516.         result = 0;
  517.     }
  518.     SetA5(theA5);
  519.     return result;
  520. }
  521.  
  522.  
  523.  
  524. /*----------------------------------------------------------------------------
  525.     BeginCriticalMemorySequence
  526.     
  527.     Begin a sequence of critical memory requests (e.g., when saving a file). 
  528.     
  529.     Exit:    savedCriticalSeq = previous value of the critical memory
  530.                 sequence state. The caller must restore this value on the
  531.                 matching call to EndCriticalMemorySequence.
  532. ----------------------------------------------------------------------------*/
  533.  
  534. void BeginCriticalMemorySequence (Boolean *savedCriticalSeq)
  535. {
  536.     *savedCriticalSeq = gCriticalSeq;
  537.     gCriticalSeq = true;
  538. }
  539.  
  540.  
  541.  
  542. /*----------------------------------------------------------------------------
  543.     EndCriticalMemorySequence
  544.     
  545.     End a sequence of critical memory requests. 
  546.     
  547.     Entry:    savedCriticalSeq = previous value of the critical memory
  548.                 sequence state, as returned on the matching call to
  549.                 BeginCriticalMemorySequence.
  550. ----------------------------------------------------------------------------*/
  551.  
  552. void EndCriticalMemorySequence (Boolean savedCriticalSeq)
  553. {
  554.     gCriticalSeq = savedCriticalSeq;
  555. }
  556.  
  557.  
  558.  
  559. /*----------------------------------------------------------------------------
  560.     HaveModernTempMemory
  561.     
  562.     Check to see if we have modern temporary memory (real and tracked). 
  563.     
  564.     Exit:    function result = true if we have modern temporary memory.
  565. ----------------------------------------------------------------------------*/
  566.  
  567. Boolean HaveModernTempMemory (void)
  568. {
  569.     OSErr err = noErr;
  570.     long response;
  571.     
  572.     #define mask ((1L << gestaltTempMemSupport) | \
  573.         (1L << gestaltRealTempMemory) | \
  574.         (1L << gestaltTempMemTracked))
  575.  
  576.     err = Gestalt(gestaltOSAttr, &response);
  577.     if (err != noErr) return false;
  578.     return (response & mask) == mask;
  579. }
  580.  
  581.  
  582.  
  583. /*----------------------------------------------------------------------------
  584.     MyTempNewHandle
  585.     
  586.     Allocate temporary memory. 
  587.     
  588.     Entry:    len = size of block to allocate.
  589.     
  590.     Exit:    *handle = new handle.
  591.             function result = error code.
  592. ----------------------------------------------------------------------------*/
  593.  
  594. OSErr MyTempNewHandle (Size len, void *handle)
  595. {
  596.     OSErr err = noErr;
  597.  
  598.     *(Handle*)handle = TempNewHandle(len, &err);
  599.     return err;
  600. }
  601.  
  602.  
  603.  
  604. /*----------------------------------------------------------------------------
  605.     InitMemUtil
  606.     
  607.     Initialize the memory utilities. 
  608.             
  609.     Entry:    cushion = size of memory cushion.
  610.             reserve = size of memory reserve block.
  611.             
  612.     Exit:    function result = error code.
  613.     
  614.     For a description of the memory cushion and reserve, see NIM:Memory.
  615. ----------------------------------------------------------------------------*/
  616.  
  617. OSErr InitMemUtil (Size cushion, Size reserve)
  618. {
  619.     OSErr err = noErr;
  620.     static GrowZoneUPP myGrowZoneUPP;
  621.  
  622.     gCushion = cushion;
  623.     gReserve = reserve;
  624.     gReserveBlock = NewHandle(reserve);
  625.     err = MemError();
  626.     if (err != noErr) return err;
  627.     myGrowZoneUPP = NewGrowZoneProc(MyGrowZone);
  628.     SetGrowZone(myGrowZoneUPP);
  629.     return noErr;
  630. }
  631.  
  632.  
  633.  
  634. /*----------------------------------------------------------------------------
  635.     RecoverReserveMemory
  636.     
  637.     Recover the reserve memory block, if possible. This function should be
  638.     called in the main event loop. 
  639.             
  640.     Exit:    function result = true if reserve block recovered and memory
  641.             cushion available.
  642. ----------------------------------------------------------------------------*/
  643.  
  644. Boolean RecoverReserveMemory (void)
  645. {
  646.     if (gReserveBlock == nil) return true;
  647.     if (*gReserveBlock != nil) return true;
  648.     ReallocateHandle(gReserveBlock, gReserve);
  649.     if (MemError() != noErr) return false;
  650.     return MemoryAvailable(0);
  651. }
  652.